import javax.imageio.stream.ImageOutputStreamImpl;
import java.io.*;
import java.net.*;
import java.util.Optional;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

//实现tcp的服务器
// tcp：
// 有连接的，可靠的，面向字节流的，
public class TcpEchoServer {
    private ServerSocket socket=null;
    //构建一个server的 端口号
    public TcpEchoServer(int port) throws IOException {
        socket=new ServerSocket(port);
    }

    /*public void start() throws IOException {
        System.out.println("服务器启动");
        while(true) {

            // 用来接收 客户端发的请求
            Socket socketClient = socket.accept();
            // 在这个构造的新方法中进行操作
            //processConnection(socketClient);

            // 当然这里可能存在文件资源泄漏的问题
            // 由于长时间的创建 Socket 的对象 不关闭， 就会导致文件描述符表可能就会被填满，导致文件资源泄露
            // 解决方法： 一： 在 processConnection（） 方法中进行关闭 利用 finally
            //          二： 在 start （） 方法中进行关闭( 存在问题 )： 当我们的processConnection方法中抛出异常，就可能执行不到下面的关闭操作了
            //socketClient.close();

            //          三： 可以直接 采取 try 的方式，自动关闭
            *//*
            * try(Socket socketClient = socket.accept()){
            * ......
            *  }
            * *//*



            // 当然上述 写法还有一些不足：
            //当我们多个客户端进行访问服务器的时候，就会出现 阻塞 的情况
            // 我们可以采用 多线程的方式进行编写
            Thread t=new Thread(()->{

                    processConnection(socketClient);

            });
            t.start();
        }
    }

    private void processConnection(Socket socketClient){
        System.out.printf("客户端上线：%s : %s \n",socketClient.getInetAddress(),socketClient.getPort());
        try(InputStream inputStream=socketClient.getInputStream();
        OutputStream outputStream=socketClient.getOutputStream()){
            while(true) {
                // 将 客户端发送的请求（字节流）放入 Scanner中
                Scanner in = new Scanner(inputStream);
                if (!in.hasNext()) {
                    System.out.println("下线");
                    break;
                }
                // 读取请求
                String request = in.next();
                // 响应
                String respond = process(request);
                // 返回客户端-----》 可以通过 OutputStream的方式写入数据
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(respond);
                printWriter.flush();

                // 写入之后，我们可以打印一下我们整个请求的过程
                System.out.printf("%s : %s ,request : %s , respond : %s\n", socketClient.getInetAddress(), socketClient.getPort(),
                        request, respond);
            }
        }catch(IOException e){
            e.printStackTrace();
        }finally{
            try {
                socketClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private String process(String request) {
        return request;
    }*/


    public void start() throws IOException {
        System.out.println("服务器启动!");
        ExecutorService service = Executors.newCachedThreadPool();
        while(true){

                Socket socketClient=socket.accept();
                service.submit(new Runnable() {
                    @Override
                    public void run() {
                        processConnection(socketClient);
                    }
                });

        }


    }

    private void processConnection(Socket socketClient){
        System.out.printf("[%s:%d] 客户端上线!\n", socketClient.getInetAddress(), socketClient.getPort());
        try(InputStream inputStream=socketClient.getInputStream();
            OutputStream outputStream=socketClient.getOutputStream()){
            while(true){
                Scanner in=new Scanner(inputStream);
                if(!in.hasNext()){
                    System.out.println("下线");
                    break;
                }
                String request=in.next();

                String respond=process(request);

                PrintWriter printWriter=new PrintWriter(outputStream);
                printWriter.println(respond);
                printWriter.flush();

                System.out.printf("[%s:%d] req=%s, resp=%s\n", socketClient.getInetAddress(), socketClient.getPort(),
                        request, respond);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer server=new TcpEchoServer(9090);
        server.start();
    }
}
